using System;
using System.Text.RegularExpressions;

using Dashboard;
using Dashboard.Util;

// FIXME: A local implementation of this might be nicer
// and of course way faster.

namespace Dashboard.Engine.Backends {

	public class GoogleCalculatorBackend : Backend, IComponent {

		private const string BeginCalculator = "<img src=/images/calc_img.gif";
		private const string BeginReply = "<td nowrap><h2 class=r><font size=+1><b>";
		private const string EndReply = "</b>";

		public void Initialize () 
		{
			Engine.MessageBroker.Subscribe ("/event/*", typeof (ClueMessage), OnMessage);
		}

		public void Dispose ()
		{
			Engine.MessageBroker.Unsubscribe (OnMessage);
		}

		private void OnMessage (Message message)
		{
			Engine.Log.Debug ("Processing message");
			
			ClueMessage clue_message = message as ClueMessage;
			MatchMessage matches_message = new MatchMessage ();

			foreach (Clue clue in clue_message.Clues) {
				if (clue.Type != "db:calculator")
					continue;
					
				if (String.IsNullOrEmpty (clue.Properties ["db:expression"].Value))
					continue;

				string expression, url, page, reply;
				int beginCalculator, beginReply, endReply;
		 
				expression = clue.Properties ["db:expression"].Value;
				url = GetUri (expression);

				try {
					page = WebpageFu.GetContent (url);
					
					// Check for the presence of the calculator image
					beginCalculator = page.IndexOf (BeginCalculator);
					if (beginCalculator < 0)
						continue;

					page = page.Substring (beginCalculator);
				
					// Try to extract the reply
					beginReply = page.IndexOf (BeginReply);
					if (beginReply < 0)
						continue;

					reply = page.Substring (beginReply + BeginReply.Length);
					endReply = reply.IndexOf (EndReply); 
					reply = reply.Substring (0, endReply);

					// Strip HTML tags
					reply = Regex.Replace (reply, @"<[^>]+>", "");

					Match match = new Match ("db:calculator");
					match.Trigger = clue_message.Id;
					match.Properties.Add (new Property ("db:expression", expression));
					match.Properties.Add (new Property ("db:result", reply));

					matches_message.Matches.Add (match);
				} catch {
					Engine.Log.Warn ("Google Calculator could not evaluate the expression.");
				}
			}
			
			if (matches_message.Matches.Count > 0)
				Engine.MessageBroker.Send (matches_message);
		}

		private string GetUri (string e)
		{
			return "http://www.google.com/search?&q=" + (e ?? "")
				.Replace ("+", "%2B")
				.Replace ("(", "%28")
				.Replace (")", "%29")
				.Replace ("/", "%2F")
				.Replace ("^", "%5E")
				.Replace (" ", "+");
		}

		public string Name {
			get { return "Google Calculator"; }
		}

		public string Description {
			get { return "Calculate an expression using the Google Calculator."; }
		}
	}
}
